vue

您所在的位置:网站首页 vue element admin登录跳转 vue

vue

2024-07-15 21:02| 来源: 网络整理| 查看: 265

*小tip:每次重新启动前端项目加载困难可以crlt+shift+delete清除浏览器缓存后再重新启动

1.前端改造

首先我们拿到项目,得了解一下目录结构

他是通过src->router->index.js,根据路由来进行页面的跳转

constantRoutes:通用页面路由

asyncRoutes:动态路由

1.1参数讲解

各个参数的意思

有子目录的目录,以最常见的table举例,table在这里,ctrl+左键点进去就行

参数与目录的对照:

1.2动态菜单思路 我们要做到的是,根据后端返回的json对象,动态的显示目录 而vue-element-admin,是写死了的菜单,所以我们调用后端接口,实现目录的拼接,最终达到实现动态菜单的目的 那么我们就要仿造router目录下index.js文件,动态的生成相似的json对象 1.3前端代码

修改router目录下的index.js中的asyncRoutes方法,使其为空,要我们动态的加入菜单

export const asyncRoutes = [ ]

首先在src->api>user.js,加入一个接口方法

//这里加一个,根据data(token)的不同,后台会返回不同的字符串结果,动态菜单完成 export function authMenu(data) { const jsonData = JSON.stringify(data); // 手动转换为 JSON 字符串 console.log("data数据是", jsonData); // 在这里添加打印语句 return request({ url: '/user/selectMenu', method: 'post', data: jsonData, // 使用转换后的 JSON 字符串 headers: { 'Content-Type': 'application/json' } }); }

修改store/modules/permission.js文件,在 generateRoutes方法里面调用上面的authMenu接口

import { asyncRoutes, constantRoutes } from '@/router' import { authMenu } from '@/api/user'// 【新加入】引入请求,后面有文件,先不慌 import Layout from '@/layout'// 【新加入】引入layout //这里自己写方法,作用就是向 asyncRoutes 插入路由,达到动态路由的效果 /** * 【新加入】后台查询的菜单数据拼装成路由格式的数据 * @param routes */ export function generaMenu(routes, data) { //data挨个遍历 data.forEach(item => { //path不为空的话,就新建一个对象,装数据 if (item.path !== '') { //这个就仿照目录的机构,搭建 const menu = { path: item.path, component: Layout, //这个不用写data里面的内容,引用就行了 redirect: item.redirect, children: [], meta: { // 使用 title 和 icon 创建 meta 对象 title: item.title, icon: item.icon } } //遍历子标签,并加入到主目录的children中去 // 判断是否有子标签 if (item.children && Array.isArray(item.children) && item.children.length > 0) { // 遍历子标签,并加入到主目录的 children 中去 item.children.forEach(childItem => { const menu2 = { path: childItem.path, component: (resolve) => require([`@/views${childItem.component}`], resolve), name: childItem.name, meta: { // 使用 title 和 icon 创建 meta 对象 title: childItem.title, icon: childItem.icon } } // 加入到主目录的 children 中去 menu.children.push(menu2) }) } //追加 routes.push(menu) } }) //把404加到最后,因为作者说 // 404 page must be placed at the end !!! const menu3 = { path: '*', redirect: '/404', hidden: true } //追加 routes.push(menu3) } const state = { routes: [], addRoutes: [] } const mutations = { SET_ROUTES: (state, routes) => { state.addRoutes = routes state.routes = constantRoutes.concat(routes) } } const actions = { generateRoutes({ commit,rootState },) { return new Promise(resolve => { const loadMenuData = [] // 保留加载动态路由的代码 // authMenu 调用可能也需要根据你的需要来决定是否删除 authMenu(rootState.user.token).then(response => { let data = response if (response.code !== 20000) { // 错误处理逻辑 } else { data = response.data Object.assign(loadMenuData, data) const tempAsyncRoutes = Object.assign([], asyncRoutes) generaMenu(tempAsyncRoutes, loadMenuData) let accessedRoutes accessedRoutes = tempAsyncRoutes || [] commit('SET_ROUTES', accessedRoutes) resolve(accessedRoutes) } }) }).catch(error => { console.log(error) }) } } export default { namespaced: true, state, mutations, actions }

最后,修改views/login下的index.vue,dispatch 一下(在登录成功的前提下)

向handleLogin中添加dispatch( "permission/generateRoutes",userRoles)

handleLogin() { this.$refs.loginForm.validate((valid) => { if (valid) { this.loading = true; // 假设有一种方法用于获取用户角色,例如 getUserRoles() const userRoles = ["admin"]; this.$store .dispatch("user/login", this.loginForm) .then(() => { // 将预定义的角色 "admin" 传递给 generateRoutes action return this.$store.dispatch( "permission/generateRoutes", userRoles ); }) .then((accessedRoutes) => { // 将动态路由添加到路由器 this.$router.addRoutes(accessedRoutes); // 导航到指定路径或默认路径 ('/') this.$router.push({ path: this.redirect || "/", query: this.otherQuery, }); // 重置加载状态 this.loading = false; }) .catch(() => { // 在登录失败的情况下重置加载状态 this.loading = false; }); } else { console.log("提交错误!!"); return false; } }); }, 2.后端改造

@Controller层

@Resource private MenuService menuService; /** * 动态菜单获取 */ @PostMapping("/selectMenu") public MenuResponse selectMenu(@RequestBody VoToken voToken) { MenuResponse res = new MenuResponse(); try { // 验证token的合法和有效性 String tokenValue = JwtUtil.verity(voToken.getToken()); if (tokenValue != null && tokenValue.startsWith(JwtUtil.TOKEN_SUCCESS)) { // 从令牌中提取实际的用户名 String username = tokenValue.replaceFirst(JwtUtil.TOKEN_SUCCESS, ""); // 记录调用日志 log.info("从令牌中提取的用户名: {}", username); // 调用 MenuService 获取菜单数据 List menus = menuService.getAllMenus(); // 记录菜单数量的日志 log.info("获取的菜单数量: {}", menus.size()); // 构建响应对象 res.setCode(Constants.STATUS_OK); res.setMsg(Constants.MESSAGE_OK); res.setData(menus); } else { // 记录token验证失败的日志 log.warn("Token验证失败"); // 验证失败 res.setCode(Constants.STATUS_FAIL); res.setMsg(Constants.MESSAGE_FAIL); } } catch (Exception e) { // 记录处理请求时发生的异常 log.error("处理请求时发生异常", e); // 处理异常 res.setCode(60204); res.setMsg("返回失败"); } return res; }

@Servicer

package com.mv.servicer; import com.mv.entity.VO.VoMenu; import java.awt.*; import java.util.List; public interface MenuService { List getAllMenus(); }

@ServiceImpl

package com.mv.servicer.Impl; import com.mv.entity.VO.VoMenu; import com.mv.mapper.MenuMapper; import com.mv.servicer.MenuService; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.awt.*; import java.util.List; @Service public class MenuServiceImpl implements MenuService { @Resource private MenuMapper menuMapper; @Override public List getAllMenus() { List allMenus = menuMapper.getAllMenus(); return VoMenu.buildMenuTree(allMenus); } // 可以根据需要添加其他方法 }

@Mapper

package com.mv.mapper; import com.mv.entity.VO.VoMenu; import org.apache.ibatis.annotations.Mapper; import java.util.List; @Mapper public interface MenuMapper { List getAllMenus(); }

@Mapper.xml

SELECT * FROM menus;

对应数据库的实体类@VoMenus

package com.mv.entity.VO; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @Data @NoArgsConstructor @AllArgsConstructor public class VoMenu { private Integer id; // 使用 Integer 类型,与数据库表中的 id 类型匹配 private String path; private String component; private String redirect; private String name; private String title; // 新增字段 title private String icon; // 新增字段 icon private Integer parent_id; // 与数据库表中的 parent_id 类型匹配 private List children; // Getters and setters // Constructors public Integer getId() { return id; } public Integer getParentId() { return parent_id; } public static List buildMenuTree(List menuList) { Map menuMap = new HashMap(); for (VoMenu menu : menuList) { menuMap.put(menu.getId(), menu); } List tree = new ArrayList(); for (VoMenu menu : menuList) { if (menu.getParentId() != null) { VoMenu parent = menuMap.get(menu.getParentId()); if (parent != null) { if (parent.getChildren() == null) { parent.setChildren(new ArrayList()); } parent.getChildren().add(menu); } } else { // 如果没有父菜单,说明是顶级菜单 tree.add(menu); } } return tree; } }

后端单方面测试 我使用的是apifox

返回数据成功。

3.数据库menus以及前端目录结构参考 3.1数据库里的父子级菜单

** 我的动态菜单获取并没有设置权限,因为我的后台只有一个管理员admin

3.2.前端目录结构

位于原项目@/views下的permission文件夹

3.3.前后端互联展示

3.3.1后端返回数据:

{ "code": 20000, "msg": "成功,", "data": [ { "id": 1, "path": "/permission", "component": "Layout", "redirect": "/permission/page", "name": "Permission", "title": "Permission", "icon": "lock", "parent_id": null, "children": [ { "id": 2, "path": "/permission/page", "component": "/permission/page", "redirect": null, "name": "PagePermission", "title": "Page Permission", "icon": null, "parent_id": 1, "children": null, "parentId": 1 }, { "id": 3, "path": "/permission/directive", "component": "/permission/directive", "redirect": null, "name": "DirectivePermission", "title": "Directive Permission", "icon": null, "parent_id": 1, "children": null, "parentId": 1 }, { "id": 4, "path": "/permission/role", "component": "/permission/role", "redirect": null, "name": "RolePermission", "title": "Role Permission", "icon": null, "parent_id": 1, "children": null, "parentId": 1 } ], "parentId": null } ] }

3.3.2前端渲染效果:

前后端互联完成。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3